package ru.spb.nicetu.altx.mnemo.cell;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import ru.spb.nicetu.altx.mnemo.extpoint.valuetypes.ITemplateValueType;
import ru.spb.nicetu.altx.mnemo.math.managers.ValueTypeClassManager;
import ru.spb.nicetu.altx.mnemo.utils.ObjectInputStreamWithLoader;

@SuppressWarnings({"serial", "unchecked"})
public class SettingNodeCell extends ManagedNodeCell implements Serializable {

  private transient ITemplateValueType value;

  public SettingNodeCell(String IDCell, String name, String valueClassName,
                         Categories category) {
    super(IDCell, name, valueClassName, category);

    // Class valueClass;
    // try {
    // valueClass =
    // this.getClass().getClassLoader().loadClass(this.getValueClassName());
    // } catch (ClassNotFoundException e1) {
    // e1.printStackTrace();
    // }

    super.calcValueTypeName();
    try {
      value = (ITemplateValueType) (super.valueTypeClass.newInstance());
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }

  }

  public ITemplateValueType getValue() {
    return value;
  }

  public void setValue(Object val) {
    if (value == null)
      return;
    value.set(val);
  }


  @Override
  public INodeCell clone() {
    SettingNodeCell copy = new SettingNodeCell(getCellID(), getName(),
        getValueClassName(), getCategorie());
    copy.valueTypeClass = this.valueTypeClass;
    copy.valueTypeName = this.valueTypeName;
    copy.value = this.value.clone();
    return copy;
  }

  private void writeObject(java.io.ObjectOutputStream out) throws IOException {
    // 1. Cохраняемcя посредством стандартного механизма
    out.defaultWriteObject();

    // 2. Сохраняем имя класса обертки
    out.writeObject(value.getClass().getName());

    // Преобразуем объект value в byte[]
    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    ObjectOutputStream myOut = new ObjectOutputStream(bOut);
    myOut.writeObject(value);
    byte[] valueToBytes = bOut.toByteArray();

    // 3. Сохраняем размер массива, которым представлен объект value
    out.writeInt(valueToBytes.length);

    // 4. Сохраняем объект value, представленный в виде byte[] в поток
    // oos.write(valueToBytes);
    for (int i = 0; i <= valueToBytes.length; i = i + 1000) {
      if (valueToBytes.length - i < 1000) {
        out.write(valueToBytes, i, (valueToBytes.length) - i);
      } else {
        out.write(valueToBytes, i, 1000);
      }
      out.flush();
    }

//    System.out.println("Serialize: " + this);
  }

  private void readObject(java.io.ObjectInputStream in) throws IOException,
      ClassNotFoundException {

    // 1. Считываемся посредством стандартного механизма
    in.defaultReadObject();

    // 2. считываем имя класса обертки
    Object classNameO = in.readObject();

    // вычисляем класс обертки
    Class clazz = ValueTypeClassManager.getInstance().getValueTypeClass(
        (String) classNameO);
    if (clazz == null) {
      value = null;
      return;
    }

    // Получаем загрузчик класса обертки. Этот загрузчик знает о классе
    // обернутого значения
    ClassLoader myLoader = clazz.getClassLoader();

    // 3. Считываем из потока размер массива, представляющего объект value
    int size = in.readInt();
    // 4. Cчитываем из потока массив byte[], которым представлен объект value
    byte[] valueToBytes = new byte[size];
    // in.read(valueToBytes);
    for (int i = 0; i <= valueToBytes.length; i = i + 1000) {
      if (valueToBytes.length - i < 1000) {
        in.read(valueToBytes, i, (valueToBytes.length) - i);
      } else {
        in.read(valueToBytes, i, 1000);
      }
    }

    // Переводим массив byte[] в Object
    ObjectInputStreamWithLoader inpS = new ObjectInputStreamWithLoader(
        new ByteArrayInputStream(valueToBytes), myLoader);

    // Считываем само значение value
    value = (ITemplateValueType) inpS.readObject();

//    System.out.println("Deserialize: " + this);
  }
}
